package cn.com.bluemoon.daps.standard.controller;


import cn.com.bluemoon.daps.common.datascope.BmPermission;
import cn.com.bluemoon.daps.common.domain.BmPageRequestVo;
import cn.com.bluemoon.daps.common.domain.ResultBean;
import cn.com.bluemoon.daps.common.toolkit.BmAssetUtils;
import cn.com.bluemoon.daps.standard.entity.DapStandardDim;
import cn.com.bluemoon.daps.standard.entity.DapStandardIndex;
import cn.com.bluemoon.daps.standard.service.DapStandardDimService;
import cn.com.bluemoon.daps.standard.service.DapStandardIndexService;
import cn.com.bluemoon.daps.standard.vo.IndexStandardVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.base.Objects;
import io.swagger.annotations.*;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 总线矩阵前端控制器
 * </p>
 *
 * @author admin
 * @since 2021-09-23
 */
@Api(tags = "矩阵总线")
@RestController
@Slf4j
@RequestMapping("/busMatrix")
public class DapBusMatrixController {

    @Autowired
    private DapStandardIndexService indexService;
    @Autowired
    private DapStandardDimService dimService;

    private static List<Column> initStaticColumns() {
        int colId = 0;
        List<Column> cols = new ArrayList<>();
        cols.add(Column.builder().colId(String.valueOf(colId++)).colName("行id").dimCol(false).build());
        cols.add(Column.builder().colId(String.valueOf(colId++)).colName("业务线").dimCol(false).build());
        cols.add(Column.builder().colId(String.valueOf(colId++)).colName("主题").dimCol(false).build());
        cols.add(Column.builder().colId(String.valueOf(colId++)).colName("一级分类").dimCol(false).build());
        cols.add(Column.builder().colId(String.valueOf(colId++)).colName("二级分类").dimCol(false).build());
        cols.add(Column.builder().colId(String.valueOf(colId++)).colName("三级分类").dimCol(false).build());
        cols.add(Column.builder().colId(String.valueOf(colId++)).colName("原子指标").dimCol(false).build());
        return cols;
    }

    private static Map<String, Object> initStaticColumnCells(BusMatrixResponse c) {
        Map<String, Object> cell = new HashMap<>();
        int cellIndex = 0;
        IndexStandardVo index = c.getIndex();
        // rowId为标准唯一id
        cell.put(String.valueOf(cellIndex++), index.getStandardUniqueId());
        cell.put(String.valueOf(cellIndex++), index.getBizLine());
        cell.put(String.valueOf(cellIndex++), index.getTopicName());
        cell.put(String.valueOf(cellIndex++), index.getFirstCategoryName());
        cell.put(String.valueOf(cellIndex++), index.getSecondCategoryName());
        cell.put(String.valueOf(cellIndex++), index.getThirdCategoryName());
        cell.put(String.valueOf(cellIndex++), index.getIndexChinName());
        return cell;
    }

    /**
     * 业务线接口 {@link DapTopicDefineBizLineController#bizLine()}
     * 主题列表接口{@link DapTopicDefineTopicCategoryController#topicList()}
     * 总线矩阵{@link this#list(BusMatrixSearchVo)}
     */

    @SuppressWarnings("unchecked")
    @BmPermission(value = {"standard:busMatrix", "standard:busMatrix:page"}, name = "指标总线矩阵", ignore = false)
    @PostMapping("/list")
    @ApiOperation(value = "指标总线矩阵")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "ok", response = Object.class)})
    public ResultBean<IPage<Map<String, Object>>> list(@RequestBody @Valid BusMatrixSearchVo searchVo) {
        BmAssetUtils.notNull(searchVo.getBuzLineId(), "请指定业务线信息，-1为全部");
        LambdaQueryWrapper<DapStandardIndex> query = indexService.bmLambdaQuery()
                .eq(searchVo.getBuzLineId() != -1, DapStandardIndex::getBizLineId, searchVo.getBuzLineId())
                .eq(StringUtils.isNotBlank(searchVo.getTopicId()), DapStandardIndex::getTheme, searchVo.getTopicId())
                .eq(DapStandardIndex::getPublishNewest, true)
                .eq(DapStandardIndex::getIndexType, 1) // 原子指标
                .like(StringUtils.isNotBlank(searchVo.stdNameTrim()), DapStandardIndex::getIndexChinName, searchVo.stdNameTrim())
                .orderByAsc(DapStandardIndex::getBizLineId, DapStandardIndex::getTheme, DapStandardIndex::getPrimarySort);
        // create index idx_blid_tid_psid_icn
        //	on dap_standard_index (biz_line_id, theme, primary_sort, index_chin_name);
        IPage<DapStandardIndex> page = indexService.page(searchVo.toMpPage(), query);
        IPage<BusMatrixResponse> busMatrixResponsePage = page.convert(d -> {
            IndexStandardVo indexStandardVo = new IndexStandardVo(d);
            indexService.transferDicInfo(d, indexStandardVo);
            return indexStandardVo;
        }).convert(index -> {
            String dims = index.getAssociationDimension();
            String[] dimArr;
            if (dims != null &&  (dimArr = dims.split(",")).length > 0) {
                LambdaQueryWrapper<DapStandardDim> in = dimService.bmLambdaQuery().in(DapStandardDim::getId, (Object[]) dimArr);
                List<DapStandardDim> list = dimService.list(in);
                return BusMatrixResponse.builder().index(index).dims(list).build();
            }
            return BusMatrixResponse.builder().index(index).dims(Collections.emptyList()).build();
        });
        List<StdDimDto> allDims = busMatrixResponsePage.getRecords().stream().flatMap(b -> b.getDims().stream()).distinct().collect(Collectors.toList());
        // 构建列(静态列+动态列）
        List<Column> columns = initStaticColumns();
        List<Column> dimCols = allDims.stream().map(s -> Column.builder().colId(s.getDimId()).colName(s.getDimName()).dimCol(true).build()).collect(Collectors.toList());
        columns.addAll(dimCols);
        // 构建数据集
        IPage<Map<String, Object>> result = busMatrixResponsePage.convert(busMatrixResponse -> {
            Map<String, Object> row = initStaticColumnCells(busMatrixResponse);
            List<StdDimDto> dims = busMatrixResponse.getDims();
            final Map<String, String> dimCell = dims.stream().collect(Collectors.toMap(StdDimDto::getDimId, StdDimDto::getDimName));
            dimCols.forEach(c -> {
                if (dimCell.containsKey(c.getColId())) {
                    row.put(c.getColId(), true);
                } else {
                    row.put(c.getColId(), false);
                }
            });
            return row;
        });
        return ResultBean.page(result).addMoreData("columns", columns);
    }

    @ToString
    @Setter
    @Getter
    @Builder
    public static class Column {
        private String colName;
        private String colId;
        private Boolean dimCol;
    }

    @ToString
    @Setter
    @Getter
    @Builder
    public static class Cell {
        private Integer colId;
        private Object value;
    }

    @Getter
    @ToString
    @Builder
    public static class BusMatrixResponse implements Serializable {
        private static final long serialVersionUID = 1L;
        private final IndexStandardVo index;
        private final List<DapStandardDim> dims;

        public List<StdDimDto> getDims() {
            return Optional.ofNullable(dims)
                    .map(ds -> ds.stream()
                            .map(d -> StdDimDto.builder().dimId(d.getId()).dimName(d.getCodeName()).build())
                            .collect(Collectors.toList()))
                    .orElse(Collections.emptyList());
        }
    }

    @Getter
    @ToString
    @Builder
    public static class StdDimDto {
        private final String dimId;
        private final String dimName;

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            StdDimDto stdDimDto = (StdDimDto) o;
            return Objects.equal(dimId, stdDimDto.dimId) &&
                    Objects.equal(dimName, stdDimDto.dimName);
        }

        @Override
        public int hashCode() {
            return Objects.hashCode(dimId, dimName);
        }
    }

    @Setter
    @Getter
    @ToString
    public static class BusMatrixSearchVo extends BmPageRequestVo implements Serializable {
        private static final long serialVersionUID = 1L;

        @ApiModelProperty(value = "业务线，-1为全部", example = "0")
        private Integer buzLineId;

//        @NotEmpty(message = "请选择主题")
        @ApiModelProperty("主题")
        private String topicId;

        @ApiModelProperty("原子指标")
        private String stdName;

        public String stdNameTrim() {
            return StringUtils.trim(this.stdName);
        }
    }
}
